package com.yuhuihui.common.mvc;

import com.yuhuihui.common.annotation.mvc.SimpleResponseBody;
import com.yuhuihui.common.annotation.result.SuccessInfo;
import com.yuhuihui.common.domain.result.ResponseResult;
import com.yuhuihui.common.domain.result.SimpleResult;
import com.yuhuihui.common.enums.ResultCodeStatusEnum;
import com.yuhuihui.common.utils.ResponseBodyInfoUtil;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;

/**
 * 统一返回格式
 * 注意：controller的返回类型不能是String，如果需要返回String类型，则使用com.yuhuihui.common.annotation.result.SuccessInfo注解
 *
 * @author yuhh
 * @date 2023-05-25 14:55:25
 * @see ResponseBodyAdvice
 */
public class SimpleResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, @Nullable Class aClass) {
        // 如果其返回值类型不为ResponseResult及其子类，且该方法有SimpleResponseBody注解或该类有SimpleResponseBody注解
        return methodParameter.getMethod() != null
                && !ResponseResult.class.isAssignableFrom(methodParameter.getMethod().getReturnType())
                && (methodParameter.hasMethodAnnotation(SimpleResponseBody.class)
                    || AnnotatedElementUtils.hasAnnotation(methodParameter.getContainingClass(), SimpleResponseBody.class));
    }

    @Override@Nullable
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter,
                                  @Nullable MediaType mediaType, @Nullable Class aClass,
                                  @Nullable ServerHttpRequest serverHttpRequest,
                                  @Nullable ServerHttpResponse serverHttpResponse) {
        // 判断该方法上是否有SuccessInfo注解
        if (methodParameter.hasMethodAnnotation(SuccessInfo.class)){
            // 先取线程变量的值
            String message = ResponseBodyInfoUtil.getMessage();
            int resultCode = ResponseBodyInfoUtil.getResultCode().code;
            boolean result = ResponseBodyInfoUtil.getResult();
            // 如果线程变量的值不为空，则说明message已经被修改了
            if (!ObjectUtils.isEmpty(message)){
                // 取完值后移除线程变量的值
                ResponseBodyInfoUtil.cleanThreadLocal();
            } else {
                // 如果线程变量的值为空，则去注解上的message默认值
                message = Objects.requireNonNull(methodParameter.getMethodAnnotation(SuccessInfo.class)).message();
            }
            return new ResponseResult<>(resultCode, message, new SimpleResult(result));
        }
        return new ResponseResult<>(ResultCodeStatusEnum.OK.code, o);
    }
}
